/** ****************************************************************************
@defgroup UART UART
@ingroup BSP
@brief 串口驱动
@addtogroup UART
@{
*******************************************************************************/

#include "stdinc.h"
#include "uart.h"


typedef void (*FUNC_UART_init)(uint32_t baudrate, USART_WordLength_TypeDef dataBits, USART_StopBits_TypeDef stopBits, USART_Parity_TypeDef parity);
typedef void (*FUNC_UART_enableIrqRx)(bool sw);
typedef void (*FUNC_UART_enableIrqTx)(bool sw);
typedef void (*FUNC_UART_rxIRQHandler)(FUNC_void_u8_voidp onRxChar, void *cookie);
typedef void (*FUNC_UART_txIRQHandler)(FUNC_void_voidp onTxComplete, void *cookie);
typedef uint8_t (*FUNC_UART_putc)(uint8_t ch);
typedef uint8_t (*FUNC_UART_getc)();

typedef struct stUARTPort {
	FUNC_UART_init init;
	FUNC_UART_enableIrqRx enableIrqRx ;
	FUNC_UART_enableIrqTx enableIrqTx ;
	FUNC_UART_rxIRQHandler rxIRQHandler;
	FUNC_UART_txIRQHandler txIRQHandler;
	FUNC_UART_putc putc;
	FUNC_UART_getc getc;
} UARTPort;


void UART1_init(uint32_t baudrate, USART_WordLength_TypeDef dataBits, USART_StopBits_TypeDef stopBits, USART_Parity_TypeDef parity) {
	UART1_DeInit();
	CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);
	UART1->CR5 = 0;
	UART1_Init(baudrate, (UART1_WordLength_TypeDef)dataBits, (UART1_StopBits_TypeDef)stopBits, (UART1_Parity_TypeDef)parity, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
	UART1_Cmd(ENABLE);
}

void UART1_enableIrqRx(bool sw) {
	// 启用接收数据中断
	UART1_ITConfig(UART1_IT_RXNE,	(FunctionalState)sw);
	UART1_ITConfig(UART1_IT_OR, 	(FunctionalState)sw);
	UART1_ITConfig(UART1_IT_RXNE_OR, 	(FunctionalState)sw);

	// 禁用其它中断
	UART1_ITConfig(UART1_IT_IDLE,	DISABLE);
	UART1_ITConfig(UART1_IT_PE, 	DISABLE);
	UART1_ITConfig(UART1_IT_LBDF, 	DISABLE);
}

void UART1_enableIrqTx(bool sw) {
	UART1_ITConfig(UART1_IT_TC, 	(FunctionalState)sw);
	UART1_ITConfig(UART1_IT_TXE, 	(FunctionalState)sw);
}

/// @brief 接收中断
void UART1_rxIRQHandler(FUNC_void_u8_voidp onRxChar, void *cookie) {
	__IO uint8_t SR = UART1->SR;
	__IO uint8_t ch = UART1->DR;

	if( (SR & UART1_FLAG_PE) || (SR & UART1_FLAG_FE) || (SR & UART1_FLAG_NF) ) {
		// 数据错误，丢弃
		return;
	}

	if( (SR & UART1_FLAG_OR) || (SR & UART1_FLAG_IDLE) ) {
		// 数据有效，继续
	}

	if(SR & UART1_IT_RXNE) {
		if(onRxChar) { onRxChar(ch, cookie); }
	}
}

/// @brief 发送完成中断
void UART1_txIRQHandler(FUNC_void_voidp onTxComplete, void *cookie) {
	if( UART1_GetITStatus(UART1_IT_TC) || UART1_GetITStatus(UART1_IT_TXE) ) {
		if(onTxComplete) {
			onTxComplete(cookie);
		} else {
			// 如果没人管，则必须将TXE中断关闭，否则会不断地产生中断，导致系统down机
			UART1_enableIrqTx(false);
		}

		UART1_ClearITPendingBit(UART1_IT_TC);
		UART1_ClearITPendingBit(UART1_IT_TXE);
		return;
	}
}

/// 单字符输出
uint8_t UART1_putc(uint8_t ch) {
	// TXE：指数据已经放入输出移位寄存器，等待逐个bit传输
	// TXC：指数据已经在数据线上传输完成
	while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
	UART1_SendData8(ch);
	return ch;
}

/// 字符输入
uint8_t UART1_getc() {
	while (UART1_GetFlagStatus(UART1_FLAG_RXNE) == RESET);
	return UART1_ReceiveData8();
}


void UART3_init(uint32_t baudrate, USART_WordLength_TypeDef dataBits, USART_StopBits_TypeDef stopBits, USART_Parity_TypeDef parity) {
	UART3_DeInit();
	CLK_PeripheralClockConfig(CLK_Peripheral_USART3, ENABLE);
	UART3_Init(baudrate, (UART3_WordLength_TypeDef)dataBits, (UART3_StopBits_TypeDef)stopBits, (UART3_Parity_TypeDef)parity, UART3_MODE_TXRX_ENABLE);
	UART3_Cmd(ENABLE);
}

void UART3_enableIrqRx(bool sw) {
	// 启用接收数据中断
	UART3_ITConfig(UART3_IT_RXNE,	(FunctionalState)sw);
	UART3_ITConfig(UART3_IT_OR, 	(FunctionalState)sw);
	UART3_ITConfig(UART3_IT_RXNE_OR, 	(FunctionalState)sw);

	// 禁用其它中断
	UART3_ITConfig(UART3_IT_IDLE,	DISABLE);
	UART3_ITConfig(UART3_IT_PE, 	DISABLE);
	UART3_ITConfig(UART3_IT_LBDF, 	DISABLE);
}

void UART3_enableIrqTx(bool sw) {
	UART3_ITConfig(UART3_IT_TC, 	(FunctionalState)sw);
	UART3_ITConfig(UART3_IT_TXE, 	(FunctionalState)sw);
}

/// @brief 接收中断
void UART3_rxIRQHandler(FUNC_void_u8_voidp onRxChar, void *cookie) {
	__IO uint8_t SR = UART3->SR;
	__IO uint8_t ch = UART3->DR;

	if( (SR & UART3_FLAG_PE) || (SR & UART3_FLAG_FE) || (SR & UART3_FLAG_NF) ) {
		// 数据错误，丢弃
		return;
	}

	if( (SR & UART3_FLAG_OR_LHE) || (SR & UART3_FLAG_IDLE) ) {
		// 数据有效，继续
	}

	if(SR & UART3_IT_RXNE) {
		if(onRxChar) { onRxChar(ch, cookie); }
	}
}

/// @brief 发送完成中断
void UART3_txIRQHandler(FUNC_void_voidp onTxComplete, void *cookie) {
	if( UART3_GetITStatus(UART3_IT_TC) || UART3_GetITStatus(UART3_IT_TXE) ) {
		if(onTxComplete) {
			onTxComplete(cookie);
		} else {
			// 如果没人管，则必须将TXE中断关闭，否则会不断地产生中断，导致系统down机
			UART3_enableIrqTx(false);
		}

		UART3_ClearITPendingBit(UART3_IT_TC);
		UART3_ClearITPendingBit(UART3_IT_TXE);
		return;
	}
}

/// 单字符输出
uint8_t UART3_putc(uint8_t ch) {
	// TXE：指数据已经放入输出移位寄存器，等待逐个bit传输
	// TXC：指数据已经在数据线上传输完成
	while (UART3_GetFlagStatus(UART3_FLAG_TXE) == RESET);
	UART3_SendData8(ch);
	return ch;
}

/// 字符输入
uint8_t UART3_getc() {
	while (UART3_GetFlagStatus(UART3_FLAG_RXNE) == RESET);
	return UART3_ReceiveData8();
}


const UARTPort _UARTPort1 = {
	UART1_init,
	UART1_enableIrqRx,
	UART1_enableIrqTx,
	UART1_rxIRQHandler,
	UART1_txIRQHandler,
	UART1_putc,
	UART1_getc,
};
UARTPort *UARTPort1 = (UARTPort*)&_UARTPort1;

const UARTPort _UARTPort3 = {
	UART3_init,
	UART3_enableIrqRx,
	UART3_enableIrqTx,
	UART3_rxIRQHandler,
	UART3_txIRQHandler,
	UART3_putc,
	UART3_getc,
};
UARTPort *UARTPort3 = (UARTPort*)&_UARTPort3;


void UART_init(UARTPort *uart, uint32_t baudrate, USART_WordLength_TypeDef dataBits, USART_StopBits_TypeDef stopBits, USART_Parity_TypeDef parity) {
	uart->init(baudrate, dataBits, stopBits, parity);
}

void UART_enableIrqRx(UARTPort *uart, bool sw) {
	uart->enableIrqRx(sw);
}

void UART_enableIrqTx(UARTPort *uart, bool sw) {
	uart->enableIrqTx(sw);
}

void UART_txIRQHandler(UARTPort *uart, FUNC_void_voidp onTxComplete, void *cookie) {
	uart->txIRQHandler(onTxComplete, cookie);
}

void UART_rxIRQHandler(UARTPort *uart, FUNC_void_u8_voidp onRxChar, void *cookie) {
	uart->rxIRQHandler(onRxChar, cookie);
}

uint8_t UART_putc(UARTPort *uart, uint8_t ch) {
	return uart->putc(ch);
}

uint8_t UART_getc(UARTPort *uart) {
	return uart->getc();
}

size_t UART_send(UARTPort *uart, const void* data, size_t len) {
	uint8_t* bytes = (uint8_t*)data;
	if(!bytes || !len) { return 0; }

	for(; len>0; len--) {
		uart->putc(*(bytes++));
	}
	return len;
}

int UART_receive(
	UARTPort *uart, 		///< 串口句柄
	void* buff,				///< 接收数据缓冲区
	size_t buffSize,		///< 需要等待的最大响应字节数
	char *okFlag,          	///< OK情况下的响应数据标志
	char *failedFlag,    	///< 异常情况下的响应数据标志
	uint16_t timeoutTotal,      	///< 响应的总超时时间(ms)
	uint16_t timeoutInterval )  	///< 响应的数据字符间隔超时时间(ms)
{
	if(!buff || !buffSize) { return 0; }
	buffSize--;	// 留一个位置给尾部 '\0'

	// 同步接收数据时，应关闭接收中断，防止数据被中断服务程序读走了
	uart->enableIrqRx(false);

	uint32_t start = osGetMs();
	uint32_t lastByteTime = 0;
	size_t len = 0;
	char *data = (char*)buff;
	data[0] = '\0';

	while(1) {
		// 收到数据
		data[len++] = uart->getc();
		lastByteTime = osGetMs();

		// 因缓冲区满中止
		if(len >= buffSize) { break; }
		// 因 OK 标志中止
		if(okFlag && strstr(data, okFlag)) { break; }
		// 因 Failed 标志中止
		if(failedFlag && strstr(data, failedFlag)) { break; }

		// 因总超时中止
		if(timeoutTotal && (osElapsedMs(start) >= timeoutTotal)) { break; }
		// 因间隔超时中止
		if(timeoutInterval && lastByteTime && (osElapsedMs(lastByteTime) >= timeoutInterval)) { break; }
	}

	data[len] = '\0';
	printf(data);
	return len;
}


/// @}
